﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using MessageCenter;
using IPMsgExpections;
using System.Net.Sockets;
using CommonUtility;
using System.Threading;
using System.Text;

namespace IPMSG
{
    /// <summary>
    /// 启动UDP监听，并加载MyInfo类
    /// </summary>
    internal class UdpAdapterServer
    {
        private static readonly UdpAdapterServer instance = new UdpAdapterServer();

        private UdpAnySourceMulticastClient udpListener;

        private byte[] byteBuff;

        //单件模式
        internal static UdpAdapterServer Instance
        {
            get { return UdpAdapterServer.instance; }
        }

        //私有构造函数
        private UdpAdapterServer()
        {
        }

        //启动UDP服务
        internal void StartUdpServer()
        {
            Log.Info("Udp listening...");

            //绑定到默认端口2425
            try
            {
                udpListener = new UdpAnySourceMulticastClient(IPAddress.Parse(ConstWords.IPMSG_BroadcastIP), 2425);
            }
            catch (Exception ex)
            {
                Log.Error(ex.Message);
                throw new NetExpection(string.Format("绑定2425端口失败.{0}", ex.Message));
            }

            MyInfo.Instance.Start();

            //开始加入广播组
            udpListener.BeginJoinGroup(
                result =>
                {
                    try
                    {
                        udpListener.EndJoinGroup(result);
                    }
                    catch (Exception ex)
                    {
                        throw new NetExpection("加入局域网广播组失败.", ex);
                    }
                },
                null);

            this.byteBuff = new byte[ConstWords.IPMSG_UDPMaxMessage];

            //开始异步接收UDP消息
            udpListener.BeginReceiveFromGroup(this.byteBuff, 0, ConstWords.IPMSG_UDPMaxMessage, new AsyncCallback(this.MessageAccepter), null);

            //广播上线消息
            BroadCastBrEntry();
        }

        //局域网广播
        internal void BroadCast(MessageModel message)
        {
            //消息转化为byte数组
            byte[] bytesToBroadcast = message.EncodingMessage();

            //向局域网中的2425端口广播
            try
            {
                udpListener.BeginSendToGroup(
                    bytesToBroadcast,
                    0,
                    bytesToBroadcast.Length,
                    result =>
                    {
                        udpListener.EndSendToGroup(result);
                    },
                    null);
            }
            catch (Exception ex)
            {
                throw new NetExpection("向局域网广播消息失败.", ex);
            }
        }

        //局域网广播通知上线
        internal void BroadCastBrEntry()
        {
            MessageBrEntry messageBrEntry = new MessageBrEntry(MyInfo.Instance.UserName, MyInfo.Instance.HostName, MyInfo.Instance.IndexPackage);

            try
            {
                BroadCast(messageBrEntry);
            }
            catch (NetExpection netEX)
            {
                Log.Error(netEX.Message);
            }
            catch (Exception ex)
            {
                Log.Error(ex.Message);
            }

            Log.Info("向局域网广播上线消息成功.");
        }

        /// <summary>
        /// 局域网广播离线
        /// </summary>
        internal void BroadCastBrExit()
        {
            MessageBrExit messageBrExit = new MessageBrExit(MyInfo.Instance.UserName, MyInfo.Instance.HostName, MyInfo.Instance.IndexPackage);

            try
            {
                BroadCast(messageBrExit);
            }
            catch (NetExpection netEX)
            {
                Log.Error(netEX.Message);
            }
            catch (Exception ex)
            {
                Log.Error(ex.Message);
            }

            Log.Info("向局域网广播离线消息成功.");
        }

        //异步接收UDP数据
        private void MessageAccepter(IAsyncResult result)
        {
            IPEndPoint remoteIEP = null;

            byte[] bytesReceive = null;

            int bytesRcvLength;

            try
            {
                //接收消息
                bytesRcvLength = udpListener.EndReceiveFromGroup(result, out remoteIEP);
                bytesReceive = new byte[bytesRcvLength];
                Array.Copy(this.byteBuff, bytesReceive, bytesRcvLength);
                Log.Debug(string.Format("Message from {0}_____{1}", remoteIEP.ToString(), Gb2312Encoding.GetString(bytesReceive)));
            }
            catch (Exception ex)
            {
                Log.Error(ex.Message);
            }

            MessageModel receiveMessage = null;
            try
            {
                //格式化为MessageModel消息格式
                receiveMessage = MessageModel.DecodingMessage(bytesReceive);
            }
            catch (IPmsgExpection ipEX)
            {
                Log.Error(ipEX.Message);
            }
            catch (Exception ex)
            {
                Log.Error(ex.Message);
            }

            RemoteUser remoteUser = null;

            if (receiveMessage != null)
            {
                //用户列表中没有当前消息的发送者
                if (!IPMsgManager.Instance.RemoteUsers.ContainsKey(receiveMessage.HostName))
                {
                    //如果当前消息为通知上线消息,则把当前用户加入用户列表
                    if (receiveMessage is MessageBrEntry || receiveMessage is MessageAnsEntry)
                    {
                        remoteUser = new RemoteUser(receiveMessage, remoteIEP, udpListener);
                        IPMsgManager.Instance.RemoteUsers.Add(remoteUser.HostName, remoteUser);
                        Log.Debug(string.Format("Create RemoteUser for HostName:{0}", receiveMessage.HostName));
                        ThreadPool.QueueUserWorkItem(new WaitCallback(this.FireUserEntry),remoteUser);
                    }
                }
                else
                {
                    remoteUser = IPMsgManager.Instance.RemoteUsers[receiveMessage.HostName];
                }

                if (remoteUser != null)
                {
                    ThreadPool.QueueUserWorkItem(new WaitCallback(remoteUser.HandleMessage), receiveMessage);
                }
            }

            Array.Clear(this.byteBuff, 0, this.byteBuff.Length);
            try
            {
                udpListener.BeginReceiveFromGroup(this.byteBuff, 0, ConstWords.IPMSG_UDPMaxMessage, new AsyncCallback(this.MessageAccepter), null);
            }
            catch (Exception ex)
            {
                Log.Error(string.Format("UDPListener异常退出广播组.{0}",ex.Message));
                //开始加入广播组
                udpListener.BeginJoinGroup(
                    joinresult =>
                    {
                        try
                        {
                            udpListener.EndJoinGroup(joinresult);
                        }
                        catch (Exception joinex)
                        {
                            throw new NetExpection("加入局域网广播组失败.", joinex);
                        }
                    },
                    null);

                this.byteBuff = new byte[ConstWords.IPMSG_UDPMaxMessage];

                //开始异步接收UDP消息
                udpListener.BeginReceiveFromGroup(this.byteBuff, 0, ConstWords.IPMSG_UDPMaxMessage, new AsyncCallback(this.MessageAccepter), null);
            }
        }

        private void FireUserEntry(object obj)
        {
            RemoteUser remoteUser = obj as RemoteUser;
            EventPublicator.Instance.OnUserEntryEvent(new UserEventArgs(remoteUser.IpEP.Address.ToString(), remoteUser.UserName, remoteUser.HostName));
        }
    }
}
